﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Linq.Expressions;
using GalaSoft.MvvmLight;
using MvvmValidation;

namespace Budget.Silver.ViewModel
{
    public abstract class BudgetViewModel : ViewModelBase
    {
        protected ValidationHelper Validator { get; private set; }

        protected BudgetViewModel()
        {
            Validator = new ValidationHelper();

            AddValidationRules();
        }

        protected virtual void AddValidationRules()
        {
        }

        protected void Validate<T>(Expression<Func<T>> expression)
        {
            var result = Validator.Validate(expression);
            if (!result.IsValid)
            {
                throw new ValidationException(result.ToString());
            }
        }

        protected void ValidateAll()
        {
            var result = Validator.ValidateAll();
            if (!result.IsValid)
            {
                throw new ValidationException(result.ToString());
            }
        }
    }

    public abstract partial class ValidatableViewModelBase : ViewModelBase, IValidatable, INotifyDataErrorInfo
    {
        protected ValidationHelper Validator { get; private set; }

        private NotifyDataErrorInfoAdapter NotifyDataErrorInfoAdapter { get; set; }

        private DataErrorInfoAdapter DataErrorInfoAdapter { get; set; }


        public ValidatableViewModelBase()
        {
            Validator = new ValidationHelper();
            NotifyDataErrorInfoAdapter = new NotifyDataErrorInfoAdapter(Validator);
            DataErrorInfoAdapter = new DataErrorInfoAdapter(Validator);

            OnCreated();
        }

        partial void OnCreated();

        void IValidatable.Validate(Action<ValidationResult> onCompleted)
        {
            Validator.ValidateAllAsync(onCompleted);
        }

        #region Implementation of INotifyDataErrorInfo

        public IEnumerable GetErrors(string propertyName)
        {
            return NotifyDataErrorInfoAdapter.GetErrors(propertyName);
        }

        public bool HasErrors
        {
            get { return NotifyDataErrorInfoAdapter.HasErrors; }
        }

        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged
        {
            add { NotifyDataErrorInfoAdapter.ErrorsChanged += value; }
            remove { NotifyDataErrorInfoAdapter.ErrorsChanged -= value; }
        }

        #endregion
    }
}